import { useState, useEffect, useMemo, useCallback, PureComponent } from 'react'

export default () => {
    const [count, setCount] = useState(0)
    const [value, setValue] = useState('')

    const expensive = useMemo(() => {
        console.log('~~expensive 调用')
        let i = 0, sum = 0
        while (i < count) {
            sum += i++
        }
        return sum
    }, [count])

    const onCallbackClick = useCallback(() => {
        let i = 0, sum = 0
        while (i < count) {
            sum += i++
        }
        return sum
    }, [count])

    return (
        <div>
            <h3>useMemo和useCallback</h3>
            <button onClick={() => setCount(count + 1)}>add</button>计数：{count} 累加：{expensive}
            <Child onCallbackClick={onCallbackClick} />
            <input value={value} onChange={e => setValue(e.target.value)} />
            <ul>
                <li>由于jsx中调用了expensive()，而输入框每次改变又引起了组件中jsx的渲染，所以输入框的动作导致不必要的expensive()计算</li>
                <li>引入useMemo：将一个函数包起来，第二个参数作为依赖项，最终返回函数的结果。这样只有依赖项有变化时才会执行，否则用缓存值，类似VUE中的计算属性</li>
                <li>例子中expensive的计算值是count上一次的</li>
                <li>父组件中每次有更新，则会创建onCallbackClick方法，对于子组件Child来说每次创建的方法都不一样，所以每次都会渲染。当使用了useCallback时，只有依赖项发生变化，这个方法才会重新创建。这样子组件中通过判断传来的方法是否同一地址即可优化刷新。</li>
                <li>useCallback的子组件只能是PureComponent的class组件，普通函数组件是不行的。</li>
            </ul>
        </div>
    )
}
class Child extends PureComponent{
    constructor(props){
        super(props)
    }
    render(){
        console.log('~~Child')
    return <div>
        <h4>子组件</h4>
        <button onClick={()=>{
           console.log('~~onCallbackClick',this.props.onCallbackClick()) 
        } }>测试callback</button>
    </div>
    }
}
/* function Child({ onCallbackClick }) {
    console.log('~~Child')
    return <div>
        <h4>子组件</h4>
        <button onClick={() => {
            console.log('~~onCallbackClick', onCallbackClick())
        }}>测试callback</button>
    </div>
} */